package algocity.modelo.almacenamiento;

import algocity.modelo.juego.*;

import java.io.*;
import java.util.HashMap;
import java.util.Map;

public class AlmacenamientoPersistente
        implements Persistible
{


    private final File directorioDeconfiguracion;
    private final File directorioJugadores;
    private File archivoPuntajes;

    public AlmacenamientoPersistente(File directorioDeconfiguracion)
    {
        this.directorioDeconfiguracion = directorioDeconfiguracion;
        this.archivoPuntajes = new File(directorioDeconfiguracion, Parametros.ALMACENAMIENTO_PUNTAJES);
        this.directorioJugadores = new File(directorioDeconfiguracion, Parametros.ALMACENAMIENTO_DIRECTORIO_JUGADOR);
    }

    public void inicializar() throws DirectorioDeConfiguracionNoInicializadoException
    {
        crearDirectorio(directorioDeconfiguracion);
        crearDirectorio(directorioJugadores);

        try
        {
            guardarPuntajes(new HashMap<String, Integer>());
        } catch (GuardarPuntajesException e)
        {
            throw  new DirectorioDeConfiguracionNoInicializadoException(directorioDeconfiguracion,e);
        }
    }

    private void crearDirectorio(File directorio) throws DirectorioDeConfiguracionNoInicializadoException
    {
        directorio.mkdirs();
        if ( ! directorio.exists() || ! directorio.isDirectory()) {
            throw new DirectorioDeConfiguracionNoInicializadoException(directorioDeconfiguracion);
        }
    }

    public void guardarPuntajes(Map<String, Integer> puntajes) throws GuardarPuntajesException
    {
        try
        {
            serializar(puntajes, archivoPuntajes);
        } catch (IOException e)
        {
            throw new GuardarPuntajesException(e);
        }
    }

    @Override
    public Map<String, Integer> getPuntajes() throws ErrorAlObtenerPuntajes
    {
        Map<String, Integer> puntajes = null;

        try
        {
            puntajes = (Map<String, Integer>) deserializar(archivoPuntajes);
        } catch (Throwable e)
        {
            throw new ErrorAlObtenerPuntajes();
        }

        return puntajes;
    }

    @Override
    public void agregarJugador(Jugador jugador) throws ErrorAlCrearJugadorException, JugadorExistenteException
    {
        String nombre = jugador.getNombre();
        File archivoJugador = archivoJugador(nombre);

        if (archivoJugador.exists())
        {
            throw new JugadorExistenteException(nombre);
        }
        try
        {
            serializar(jugador, archivoJugador);
        } catch (IOException e)
        {
            throw new ErrorAlCrearJugadorException(nombre, e);
        }
    }

    @Override
    public Jugador getJugador(String nombre) throws ErrorAlObtenerJugadorException
    {

        Jugador jugador = null;

        try
        {
            jugador = (Jugador) deserializar(archivoJugador(nombre));
        } catch (Throwable e)
        {
            throw new ErrorAlObtenerJugadorException(nombre, e);
        }

        return jugador;
    }

    private File archivoJugador(String nombre)
    {
        return new File(directorioJugadores, nombre);
    }

    @Override
    public void borrarJugador(String nombre) throws JugadorInexistenteException
    {
        File archivoJugador = archivoJugador(nombre);
        if (!archivoJugador.exists())
        {
            throw new JugadorInexistenteException(nombre);
        }
        archivoJugador.delete();
    }

    public void guardarJugador(Jugador jugador)
            throws ErrorAlGuardarJugadorException
    {
        String nombre = jugador.getNombre();
        try
        {
            serializar(jugador, archivoJugador(nombre));
        } catch (Throwable e)
        {
            throw new ErrorAlGuardarJugadorException(nombre, e);
        }
    }

    private void serializar(Object puntajes, File archivo) throws IOException
    {
        FileOutputStream fileOutputStream = new FileOutputStream(archivo);
        ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream);
        objectOutputStream.writeObject(puntajes);
        objectOutputStream.close();
        fileOutputStream.close();
    }


    private Object deserializar(File archivo) throws IOException, ClassNotFoundException
    {
        FileInputStream fileInputStream = new FileInputStream(archivo);
        ObjectInputStream objectInputStream = new ObjectInputStream(fileInputStream);

        Object deserializado = objectInputStream.readObject();

        objectInputStream.close();
        fileInputStream.close();

        return deserializado;
    }
}
